package com.systar.activity.process;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.systar.activity.events.IActivityEvent;

public class ActivityStack
{
	/** Event dispatch methods */
	private enum EventDispatchMethod
	{
		/** Get events 1 by 1 */
		OneByOne,
		/** Get events by copying all events in a new list */
		ListCopy,
		/** Get events by swapping the event list with a new list */
		ListSwap;
	}

	/** Selected Event dispatch method */
	private static final EventDispatchMethod SYNC_METHOD = EventDispatchMethod.ListSwap;
	/** Set to true to compact event by map/reduce */
	private static final boolean COMPACT_EVENTS = true;

	/** Main event stack */
	private ArrayList<IActivityEvent> inputStack;
	/** Event compactor */
	private ActivitySortReduce compactor;
	/** event delegation */
	private ActivityStack delegate;

	public ActivityStack()
	{
		inputStack = new ArrayList<IActivityEvent>();
		if (COMPACT_EVENTS)
		{
			compactor = new ActivitySortReduce();
		}
	}
	
	/**
	 * Enqueue a delegation
	 * Set the delegate to the last element of the delegation chain 
	 * 
	 * @return the stack to delegate
	 */
	public ActivityStack createDelegation()
	{
		if (delegate == null)
		{
			delegate = new ActivityStack();
			return delegate;
		}
		return delegate.createDelegation();
	}

	public void add(IActivityEvent event)
	{
		synchronized (inputStack)
		{
			inputStack.add(event);
		}
		if (delegate != null)
		{
			delegate.add(event);
		}
	}

	public List<IActivityEvent> get()
	{
		ArrayList<IActivityEvent> outputStack = null;

		synchronized (inputStack)
		{ /* BEGIN synchronized block */
			if (!inputStack.isEmpty())
			{
				switch (SYNC_METHOD)
				{
				case OneByOne:
					{
						outputStack = new ArrayList<IActivityEvent>();
						outputStack.add(inputStack.remove(0));
					}
					break;

				case ListCopy:
					{
						outputStack = new ArrayList<IActivityEvent>();
						outputStack.addAll(inputStack);
						inputStack.clear();
					}
					break;

				case ListSwap:
					{
						outputStack = inputStack;
						inputStack = new ArrayList<IActivityEvent>(outputStack.size());
					}
					break;
				}
			}
		} /* END synchronized block */
		if (outputStack == null)
			return Collections.emptyList();


		if (compactor != null)
		{
			return compactor.process(outputStack);
		}
		return outputStack;
	}
}
